package fem2.element.crack_sda2;

import inf.jlinalg.SolveFailedException;
import inf.text.ArrayFormat;

import org.junit.Test;

import fem2.Constraint;
import fem2.Element;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshPart;
import fem2.Model;
import fem2.analysis.Analysis;
import fem2.analysis.LinearStaticAnalysis;
import fem2.analysis.NonlinearStaticAnalysis;
import fem2.enu.EchoLevelType;
import fem2.enu.State;
import fem2.material.FluencyCriteria;
import fem2.material.StVenantKirchhoffMM;
import fem2.material.cohesive_law2.CohesiveLaw;
import fem2.material.cohesive_law2.IsotropicDamageCohesiveLaw;
import fem2.observer.StressObserver;

public class PatchTestSOSConstantJumpCSTElementUsingIsotropicDamageCohesiveLaw extends
		PatchTestSOSConstantJumpCSTElementUsingSanchoCohesiveLaw {

	public MaterialModel createMaterial() {
		double E = 2;
		double nu = 0.3;
		double t = 1.0;
		State ss = State.PLANE_STRESS;
		return new StVenantKirchhoffMM(E, nu, t, 0, ss);
	}

	public CohesiveLaw createCohesiveLaw() {
		double H = -1;
		final double ft = 0.91;
		final double Gf = -(ft * ft) / (2 * H);

		FluencyCriteria softeningRule = new FluencyCriteria() {

			@Override
			public double computeFluencyValue(double v) {
				return ft * Math.exp(-v * ft / Gf);
			}

			@Override
			public double computeFluencyDerivative(double v) {
				double f = computeFluencyValue(v);
				return -(ft / Gf) * f;
			}
		};

		return new IsotropicDamageCohesiveLaw(Gf, ft, softeningRule);
	}

	public Element createElement(MeshPart mp, MaterialModel mm, CohesiveLaw cl) {
		return new SOSConstantJumpCSTElement(mp, mm, cl);
	}

	@Test
	public void testSolve1() throws SolveFailedException {

		Model m = createModel(createMeshT3());

		Mesh mesh = m.getMesh();

		double du = 1;
		Constraint c1 = new Constraint(false, false);
		c1.setValue(0, du);
		Constraint c2 = new Constraint(false, true);
		c2.setValue(0, du);
		mesh.getNode(1).setConstraint(c1);
		mesh.getNode(2).setConstraint(c2);

		Analysis an = new NonlinearStaticAnalysis(m, 10);
		an.getStrategy().addObserver(new StressObserver(m));
		// an.getStrategy().setEchoLevel(EchoLevelType.DEBUG);
		an.getStrategy().setEchoLevel(EchoLevelType.OUTPUT);
		// ((NonlinearStaticAnalysis) an).initializeTimeFactor(10);
		an.run();

		/*
		 * print the displacement and check with theoretical values
		 */
		System.out.println("testSolve1 results:");
		// double[][] Uh = new double[][] { { 0, 0 }, { 0.5, 0 }, { 0.5, -0.15
		// }, { 0, -0.15 } };
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			// Assert.assertEquals(Uh[i][0], uHatLocal[0], 1e-10);
			// Assert.assertEquals(Uh[i][1], uHatLocal[1], 1e-10);
		}
	}

	@Test
	public void testSolve2() throws SolveFailedException {

		Model m = createModel(createMeshQ4());

		Mesh mesh = m.getMesh();

		double du = 1;
		Constraint c1 = new Constraint(false, false);
		c1.setValue(0, du);
		Constraint c2 = new Constraint(false, true);
		c2.setValue(0, du);
		mesh.getNode(1).setConstraint(c1);
		mesh.getNode(2).setConstraint(c2);

		Analysis an = new LinearStaticAnalysis(m);
		an.getStrategy().addObserver(new StressObserver(m));
		// an.getStrategy().setEchoLevel(EchoLevel.DEBUG);
		an.getStrategy().setEchoLevel(EchoLevelType.OUTPUT);
		((NonlinearStaticAnalysis) an).initializeTimeFactor(10);
		an.run();

		/*
		 * print the displacement and check with theoretical values
		 */
		System.out.println("testSolve2 results:");
		// double[][] Uh = new double[][] { { 0, 0 }, { 0.5, 0 }, { 0.5, -0.15
		// }, { 0, -0.15 } };
		for (int i = 0; i < 4; i++) {
			double[] uHatLocal = m.getMesh().getNode(i).getUHatLocal();
			System.out.println(ArrayFormat.format(uHatLocal));
			// Assert.assertEquals(Uh[i][0], uHatLocal[0], 1e-10);
			// Assert.assertEquals(Uh[i][1], uHatLocal[1], 1e-10);
		}
	}
}
